﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Threading;
using System.IO;
using System.Net;

using Factonomy.AzureStorageUtility.WindowsApp.Resources;
using Factonomy.AzureStorageUtility.WindowsApp.Azure;
using Factonomy.AzureStorageUtility.WindowsApp.Azure.Storage;

namespace Factonomy.AzureStorageUtility.WindowsApp.UI.Forms
{
    public partial class Main : Form
    {
        /// <summary>
        /// A management class for handling blob storage
        /// </summary>
        private BlobManager _blobManager = new BlobManager();

        /// <summary>
        /// A management class for the apps resources
        /// </summary>
        private ResourceManager _resource = new ResourceManager();

        /// <summary>
        /// Returns the container name.  This is the first selected item in the container list
        /// </summary>
        /// <returns></returns>
        public string GetContainer()
        {
            // if its currently on a different thread then invoke this method
            if (InvokeRequired)
            {
                return this.Invoke(new NoParameterStringDelegate(this.GetContainer)) as string;
            }

            // return the first selected item from the list
            return this.uiListViewContainers.SelectedItems[0].Text;
        }

        /// <summary>
        /// A thread to manage the progress bar
        /// </summary>
        //private Thread _progressThread;

        public Main()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.Show();

            try
            {
                // initialize the forms text
                this.Text = Globals.AppName;

                // set the window icon
                this.Icon = ResourceManager.GetAppIcon();

                // initialize the status message
                this.ShowMessage(string.Empty);

                // initialize the blob properties controls
                this.UpdateBlobProperties(null);

                // call the resize handler to make sure the ui is correct
                this.Main_Resize(null, null);

                // initialize the account menus and blob manager
                this.InitializeAccounts();

                // add all the ui event handlers
                this.uiCloseToolStripMenuItem.Click += new EventHandler(uiCloseToolStripMenuItem_Click);
                this.uiAboutToolStripMenuItem.Click += new EventHandler(uiAboutToolStripMenuItem_Click);
                this.uiRefreshToolStripMenuItem.Click += new EventHandler(uiRefreshToolStripMenuItem_Click);
                this.uiListViewContainers.Click += new EventHandler(uiListViewContainers_Click);
                this.uiListViewContainers.SelectedIndexChanged += new EventHandler(uiListViewContainers_SelectedIndexChanged);
                this.uiListViewContainers.DoubleClick += new EventHandler(uiListViewContainers_DoubleClick);
                this.uiListViewContainers.SmallImageList = _resource.SmallIconList;
                this.uiListViewBlobs.Click += new EventHandler(uiListViewBlobs_Click);
                this.uiListViewBlobs.DoubleClick += new EventHandler(uiListViewBlobs_DoubleClick);
                this.uiListViewBlobs.SelectedIndexChanged += new EventHandler(uiListViewBlobs_SelectedIndexChanged);
                this.uiAddDirectoryToolStripMenuItem.Click += new EventHandler(uiAddDirectoryToolStripMenuItem_Click);
                this.uiAddFileToolStripMenuItem.Click += new EventHandler(uiAddFileToolStripMenuItem_Click);
                this.uiOptionsToolStripMenuItem.Click += new EventHandler(uiOptionsToolStripMenuItem_Click);
                this.uiAddContainerToolStripMenuItem.Click += new EventHandler(uiAddContainerToolStripMenuItem_Click);
                this.uiDeleteContainerToolStripMenuItem.Click += new EventHandler(uiDeleteContainerToolStripMenuItem_Click);
                this.uiDeleteToolStripMenuItem.Click += new EventHandler(uiDeleteToolStripMenuItem_Click);
                this.uiDeleteAllToolStripMenuItem.Click += new EventHandler(uiDeleteAllToolStripMenuItem_Click);
                this.uiViewToolStripMenuItem.Click += new EventHandler(uiViewToolStripMenuItem_Click);

                // add a handler to the resize event
                this.Resize += new EventHandler(Main_Resize);

                // add all the ui event handlers for the blob manager
                this._blobManager.AddBlob += new BlobManager.AddBlobDelegate(blob_AddBlob);
                this._blobManager.ShowBlob += new BlobManager.ListViewDelegate(blob_Changed);
                this._blobManager.RemoveBlobs += new BlobManager.RemoveItemDelegate(blob_RemoveBlobs);
                this._blobManager.ShowContainer += new BlobManager.ListViewDelegate(container_Changed);
                this._blobManager.Error += new BlobManager.ErrorDelegate(this.ShowMessage);
                this._blobManager.Loaded += new BlobManager.NoParameterDelegate(_blobManager_Loaded);
                this._blobManager.LoadError += new BlobManager.ErrorDelegate(_blobManager_LoadError);
                this._blobManager.Complete += new BlobManager.NoParameterDelegate(_blobManager_Complete);

                // try and load the blob manager
                this._blobManager.Load();

                // if the storage account is null then the manager failed to load a valid account
                if (this._blobManager.BlobStorage == null)
                {
                    // show a message to the user
                    this.uiStatusAccount.Text = string.Empty;
                    this.ShowMessage("Unable to load an account.  Please check the configuration file.");
                }
                else
                {
                    // show the selected account details in the ui
                    this.ShowSelectedAccount();

                    // auto update the container list if its set in the config
                    this.AutoUpdateContainerList();
                }
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (this.Owner != null)
            {
                this.Owner.Close();
            }

            ////////if (this._progressThread != null)
            ////////{
            ////////    this._progressThread.Abort();
            ////////}
            base.OnClosing(e);
        }

        /// <summary>
        /// Responds when the user tries to view a blob.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiViewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // open the window to view the blob
            this.ViewBlob(uiListViewBlobs);
        }

        /// <summary>
        /// Starts the progress bar.
        /// </summary>
        void StartProgress()
        {
            this.Cursor = Cursors.WaitCursor;
            //////// initialize the progress bar settings
            //////this.uiProgressBar.Value = 0;
            //////this.uiProgressBar.Minimum = 0;
            //////this.uiProgressBar.Maximum = 100;
            //////this.uiProgressBar.Step = 10;
            
            //////// create and start a new background thread to update the progress bar
            //////this._progressThread = new Thread(new ThreadStart(UpdateProgress));
            //////this._progressThread.IsBackground = true; 
            //////this._progressThread.Start();
        }

        /// <summary>
        /// Update the progress bar.
        /// </summary>
        void UpdateProgress()
        {
            ////////// update the progress bar
            ////////this.BeginInvoke(new NoParameterDelegate(UpdateProgressControl));

            ////////// sleep the thread and then increment the bar again
            ////////Thread.Sleep(TimeSpan.FromMilliseconds(500));
            ////////this.UpdateProgress();
        }

        /// <summary>
        /// Stops the progress bar.
        /// </summary>
        void StopProgress()
        {
            //if this is running on the wrong thread
            if (InvokeRequired)
            {
                this.Invoke(new NoParameterDelegate(StopProgress));
                return;
            }

            this.Cursor = Cursors.Default;

            //////////// if the thread is instansiated then abort it
            //////////if (this._progressThread != null)
            //////////{
            //////////    this._progressThread.Abort();
            //////////}

            //////////// reset the progress bar
            //////////this.uiProgressBar.Value = this.uiProgressBar.Maximum;
        }

        /// <summary>
        /// Update the actual progress bar control.
        /// </summary>
        public void UpdateProgressControl()
        {
            if (uiProgressBar.Value == uiProgressBar.Maximum)
            {
                uiProgressBar.Value = this.uiProgressBar.Minimum;
            }
            else
            {
                uiProgressBar.PerformStep();
            }
        }

        /// <summary>
        /// Responds when the user wants to delete all blobs from a container.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiDeleteAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Really delete?", "Confirm delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // delete all the blobs from the current container
                this._blobManager.DeleteAllBlobs(this.GetContainer());

                // update the list of blobs
                this.UpdateBlobListView();
            }
        }

        /// <summary>
        /// Responds when a user wants to delete a single blob.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiDeleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Really delete?", "Confirm delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // Delete the selected blob
                this._blobManager.DeleteBlob(this.GetContainer(), this.uiListViewBlobs.SelectedItems[0].Text);

                // update the list of blobs
                this.UpdateBlobListView();
            }
        }

        /// <summary>
        /// Handles the select index changed event for the blobs listview.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewBlobs_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.UpdateUI(Globals.UpdateUiEvent.BlobClicked);
        }

        

        /// <summary>
        ///  Handles the select index changed event for the containers listview.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewContainers_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.UpdateUI(Globals.UpdateUiEvent.ContainerClicked);
        }

        /// <summary>
        /// Updates the ui to disable/enable items based on what the user has clicked on.
        /// </summary>
        /// <param name="uiEvent"></param>
        private void UpdateUI(Globals.UpdateUiEvent uiEvent)
        {
            if (uiEvent == Globals.UpdateUiEvent.AccountClicked)
            {
            }

            if (uiEvent == Globals.UpdateUiEvent.ContainerClicked)
            {
                this.uiDeleteToolStripMenuItem.Enabled = false;
                this.uiViewToolStripMenuItem.Enabled = false;

                if (this.uiListViewContainers.SelectedItems.Count == 0)
                {
                    this.uiDeleteContainerToolStripMenuItem.Enabled = false;
                    this.uiAddFileToolStripMenuItem.Enabled = false;
                    this.uiAddDirectoryToolStripMenuItem.Enabled = false;
                    this.uiDeleteAllToolStripMenuItem.Enabled = false;
                }
                else
                {
                    this.uiDeleteContainerToolStripMenuItem.Enabled = true;
                    this.uiAddFileToolStripMenuItem.Enabled = true;
                    this.uiAddDirectoryToolStripMenuItem.Enabled = true;
                    this.uiDeleteAllToolStripMenuItem.Enabled = true;
                }
            }

            if (uiEvent == Globals.UpdateUiEvent.LoadError)
            {
                this.uiRefreshToolStripMenuItem.Enabled = false;
                this.uiAddContainerToolStripMenuItem.Enabled = false;
                this.uiDeleteContainerToolStripMenuItem.Enabled = false;
                this.uiAddFileToolStripMenuItem.Enabled = false;
                this.uiAddDirectoryToolStripMenuItem.Enabled = false;
            }

            if (uiEvent == Globals.UpdateUiEvent.BlobClicked)
            {
                if (this.uiListViewBlobs.SelectedItems.Count == 0)
                {
                    this.uiDeleteToolStripMenuItem.Enabled = false;
                    this.uiViewToolStripMenuItem.Enabled = false;
                }
                else
                {
                    this.uiDeleteToolStripMenuItem.Enabled = true;
                    this.uiViewToolStripMenuItem.Enabled = true;
                }
            }
        }

        

        /// <summary>
        /// Check whether the container list should be automatically updated.
        /// </summary>
        private void AutoUpdateContainerList()
        {
            if (Globals.AutoRefreshContainersSetting != null)
            {
                bool result = false;

                if (bool.TryParse(Globals.AutoRefreshContainersSetting, out result))
                {
                    this.UpdateContainerList();
                }
            }
        }

        /// <summary>
        /// Handles the event when the user tries to delete a container.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiDeleteContainerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ShowMessage(string.Empty);

            if (MessageBox.Show("Really delete " + this.GetContainer() + "?", "Confirm delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                try
                {
                    // delete the container
                    if (this._blobManager.DeleteContainer(this.GetContainer()))
                    {
                        // update the container and blobs list views
                        this.UpdateContainerList();
                        this.uiListViewBlobs.Items.Clear();
                    }
                }
                catch (Exception ex)
                {
                    this.ShowMessage(ex.Message);
                }
            }
        }

        /// <summary>
        /// Handles the event when a user wants to add a container.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiAddContainerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // open a dialog to prompt for a string
            PromptForString prompt = new PromptForString("Please enter a container name", "Add");
            prompt.ReturnValue += new EventHandler(AddContainer);
            prompt.ShowDialog();
        }

        /// <summary>
        /// Handles the event when the add container dialog returns a value.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void AddContainer(object sender, EventArgs e)
        {
            try
            {
                // the dialog is sent in the sender parameter
                PromptForString prompt = (PromptForString)sender;

                // use the blob manager to add a container
                this._blobManager.AddContainer(prompt.Value.ToLower());

                // update the container list
                this.UpdateContainerList();

                // close the prompt
                prompt.Close();

            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Handles the event when the user clicks on the options menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiOptionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Options options = new Options();
            options.ShowDialog();
        }

        /// <summary>
        /// Handles the event when the user clicks on the container list view.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewContainers_Click(object sender, EventArgs e)
        {
            // start the progress bar
            StartProgress(); 

            // if there is a selected item
            if (this.uiListViewContainers.SelectedItems.Count > 0)
            {
                // update the ui
                this.UpdateUI(Globals.UpdateUiEvent.ContainerClicked);

                // if the blobs should be auto refreshed then display them
                if (Globals.AutoRefreshBlobsSetting != null)
                {
                    if (bool.Parse(Globals.AutoRefreshBlobsSetting))
                    {
                        if (InvokeRequired)
                        {
                            this.BeginInvoke(new NoParameterDelegate(UpdateBlobListView));
                            return;
                        }

                        this.UpdateBlobListView();
                    }
                }
            } 
        }

        /// <summary>
        /// Responds when the user wants to add a new blob.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiAddFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ShowMessage(string.Empty);
            
            // show the add new file dialog
            AddNewFile dialog = new AddNewFile();
            dialog.AddFile += new AddNewFile.MyAddFileDelegate(dialog_AddFile);
            dialog.ShowDialog();
        }

        /// <summary>
        /// Responds when the user clicks the add button on the add file dialog.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="blobName"></param>
        void dialog_AddFile(string fileName, string blobName)
        {
            // create a new thread to add the blob
            Thread thread = new Thread(new ParameterizedThreadStart(UploadFile));
            thread.IsBackground = true;
            thread.Start(new AddBlobDetails(fileName, blobName));
        }

        /// <summary>
        /// Add a new blob.
        /// </summary>
        /// <param name="details"></param>
        private void UploadFile(object details)
        {
            AddBlobDetails addBlobDetails = (AddBlobDetails)details;
            this._blobManager.AddFile(this.GetContainer(), addBlobDetails.FileName, addBlobDetails.BlobName);
        }

        

        /// <summary>
        /// Responds when the user wants to add a directory.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiAddDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ShowMessage(string.Empty);

            // show the add directory dialog
            AddNewDirectory dialog = new AddNewDirectory();
            dialog.AddDirectory += new AddNewDirectory.MyAddDirectoryDelegate(dialog_AddDirectory);
            dialog.ShowDialog();
        }

        /// <summary>
        /// Responds when the user clicks the add button in the add directory dialog.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="rootName"></param>
        void dialog_AddDirectory(string path, string rootName)
        {
            // create a thread to add the directory
            Thread thread = new Thread(new ParameterizedThreadStart(UploadDirectory));
            thread.IsBackground = true;
            thread.Start(new AddBlobDetails(path, rootName));
        }

        /// <summary>
        /// Adds a directory to a container.
        /// </summary>
        /// <param name="details"></param>
        private void UploadDirectory(object details)
        {
            AddBlobDetails addBlobDetails = (AddBlobDetails)details;
            this._blobManager.AddDirectory(this.GetContainer(), addBlobDetails.FileName, addBlobDetails.BlobName);
            //this._blobManager.AddFile(this._container, addBlobDetails.FileName, addBlobDetails.BlobName);
        }

        /// <summary>
        /// Responds when the user double clicks on the blob list view.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewBlobs_DoubleClick(object sender, EventArgs e)
        {
            this.ViewBlob((ListView)sender);
        }

        /// <summary>
        /// View a blob.
        /// </summary>
        /// <param name="list"></param>
        public void ViewBlob(ListView list)
        {
            try
            {
                this.ShowMessage(string.Empty);

                // only carry on if there are selected items
                if (list.SelectedItems.Count > 0)
                {
                    // gets the extension of the selected item. 
                    if (Path.GetExtension(list.SelectedItems[0].Text) != string.Empty)
                    {
                        // check whether the blob can be viewed in a text viewer
                        if (Globals.CanEditInTextEditor(Path.GetExtension(list.SelectedItems[0].Text)))
                        {
                            // create and show the text viewer
                            TextViewer viewer = new TextViewer(this._blobManager.Account.AccountName, this.GetContainer(), list.SelectedItems[0].Text);
                            viewer.ShowDialog();
                        }
                        else
                        {
                            // get the blob properties to retrieve the content type
                            BlobProperties prop = this._blobManager.GetBlobProperties(this.GetContainer(), list.SelectedItems[0].Text);

                            // if the content type is an image then show the image in the image viewer
                            if (prop.ContentType.StartsWith("image/"))
                            {
                                ImageViewer imageViewer = new ImageViewer(this._blobManager.Account.AccountName, this.GetContainer(), list.SelectedItems[0].Text);
                                imageViewer.ShowDialog();
                            }
                            else
                            {
                                // default to trying to browse to the blob
                                WebBrowser browser = new WebBrowser();
                                browser.Navigate(prop.Uri);
                                browser.ShowSaveAsDialog();
                            }
                        }

                    }
                }
                else
                {
                    this.ShowMessage("Unable to open this type of file.");
                }
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Update the UI to show the blob properties.
        /// </summary>
        /// <param name="prop"></param>
        private void UpdateBlobProperties(BlobProperties prop)
        {
            try
            {
                if (prop != null)
                {
                    this.uiLabelContentType.Text = prop.ContentType;
                    this.uiLabelEncoding.Text = prop.ContentEncoding;
                    this.uiLabelETag.Text = prop.ETag;
                    this.uiLabelLanguage.Text = prop.ContentLanguage;
                    this.uiLabelLastModified.Text = prop.LastModifiedTime.ToString("G");
                    this.uiLabelName.Text = prop.Name;
                    this.uiLabelSize.Text = prop.ContentLength.ToString();
                    this.uiLabelURI.Text = prop.Uri.ToString();
                }
                else
                {
                    this.uiLabelContentType.Text = string.Empty;
                    this.uiLabelEncoding.Text = string.Empty;
                    this.uiLabelETag.Text = string.Empty;
                    this.uiLabelLanguage.Text = string.Empty;
                    this.uiLabelLastModified.Text = string.Empty;
                    this.uiLabelName.Text = string.Empty;
                    this.uiLabelSize.Text = string.Empty;
                    this.uiLabelURI.Text = string.Empty;
                }
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the user clicks on the blobs list view.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewBlobs_Click(object sender, EventArgs e)
        {
            try
            {
                // start the progress bar
                this.StartProgress();

                // get the list
                ListView list = (ListView)sender;

                // if an item is selected
                if (list.SelectedItems.Count > 0)
                {
                    // get the blobs properties
                    BlobProperties prop = this._blobManager.GetBlobProperties(this.GetContainer(), list.SelectedItems[0].Text);

                    // display the properties
                    this.UpdateBlobProperties(prop);
                }
                else
                {
                }

                // update the ui
                this.UpdateUI(Globals.UpdateUiEvent.BlobClicked);

            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Updates the container list.
        /// </summary>
        /// <param name="blob"></param>
        public void UpdateContainersList(object blob)
        {
            try
            {
                ((BlobManager)blob).ListContainers();
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        

        /// <summary>
        /// Updates the blob list view.
        /// </summary>
        private void UpdateBlobListView()
        {
            try
            {
                this.ShowMessage(string.Empty);
                Thread thread = new Thread(new ParameterizedThreadStart(UpdateBlobList));
                thread.IsBackground = true;
                thread.Start(this._blobManager);
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the user double clicks on a container.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiListViewContainers_DoubleClick(object sender, EventArgs e)
        {
            // if the blobs should be auto refreshed then display them
            if (Globals.AutoRefreshBlobsSetting == null)
            {
                if (!bool.Parse(Globals.AutoRefreshBlobsSetting))
                {
                    if (InvokeRequired)
                    {
                        this.BeginInvoke(new NoParameterDelegate(UpdateBlobListView));
                        return;
                    }

                    this.UpdateBlobListView();
                }
            }
        }

        /// <summary>
        /// Update the blob list.
        /// </summary>
        /// <param name="blob"></param>
        public void UpdateBlobList(object blob)
        {
            try
            {
                ((BlobManager)blob).ListBlobs(this.GetContainer());
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the user clicks on the refresh menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiRefreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.UpdateContainerList();
            this.UpdateUI(Globals.UpdateUiEvent.ContainerClicked);
        }

        /// <summary>
        /// Updates the container list view.
        /// </summary>
        private void UpdateContainerList()
        {
            try
            {
                this.ShowMessage(string.Empty);

                // clear both list views
                this.uiListViewContainers.Items.Clear();
                this.uiListViewBlobs.Items.Clear();

                // create a new thread to update the container list
                Thread thread = new Thread(new ParameterizedThreadStart(UpdateContainersList));
                thread.IsBackground = true;
                thread.Start(this._blobManager);
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the user clicks on the about menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiAboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About about = new About();
            about.ShowDialog();
        }

        /// <summary>
        /// Responds when the user clicks on the close menu item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void uiCloseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        ///  Resizes the UI.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Main_Resize(object sender, EventArgs e)
        {
            try
            {
                this.ResizeSplitters();
                int columnWidth = 150;

                foreach (ColumnHeader column in this.uiListViewBlobs.Columns)
                {
                    if (column.Index != 0)
                    {
                        column.Width = columnWidth;
                    }
                }

                this.uiListViewBlobs.Columns[0].Width = uiListViewBlobs.Width - (columnWidth * (this.uiListViewBlobs.Columns.Count - 1));
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Resizes the split panels in the UI.
        /// </summary>
        private void ResizeSplitters()
        {
            try
            {
                this.uiSplitContainerMain.SplitterDistance = 250;
                this.uiSplitContainerSub.SplitterDistance = this.uiSplitContainerSub.Height - 200;
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Initialises the accounts menu and adds the sub menus.
        /// </summary>
        private void InitializeAccounts()
        {
            try
            {
                // default the status text
                this.uiStatusAccount.Text = string.Empty;

                // check that the accounts setting exists
                if (ConfigurationManager.AppSettings["accounts"] == null)
                {
                    this.uiStatusAccount.Text = string.Empty;
                    this.ShowMessage("Unable to find an accounts in the configuration file.");
                }
                else
                {
                    // get all the accounts and add them to the menu
                    string[] accounts = ConfigurationManager.AppSettings["accounts"].Split('|');
                    this.uiAccountsToolStripMenuItem.DropDownItems.Clear();

                    foreach (string account in accounts)
                    {
                        ToolStripMenuItem item = new ToolStripMenuItem(account);
                        item.Name = account;

                        // if the blob manager can't find the correct settings for this account then disable the menu item
                        if (!BlobManager.AccountExists(account))
                        {
                            item.Enabled = false;
                            item.ToolTipText = "This account does not appear to have the correct settings in the configuration file.";
                        }

                        // add the menu item
                        this.uiAccountsToolStripMenuItem.DropDownItems.Add(item);
                    }

                    // set up the event handler for the click event
                    this.uiAccountsToolStripMenuItem.DropDownItemClicked += new ToolStripItemClickedEventHandler(accountsToolStripMenuItem_DropDownItemClicked);
                }
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Updates the UI to show the selected account.
        /// </summary>
        private void ShowSelectedAccount()
        {
            ((ToolStripMenuItem)this.uiAccountsToolStripMenuItem.DropDownItems[this._blobManager.Account.AccountName]).Checked = true;
            ((ToolStripMenuItem)this.uiAccountsToolStripMenuItem.DropDownItems[this._blobManager.Account.AccountName]).Select();
            this.uiStatusAccount.Text = "Account: " + this.uiAccountsToolStripMenuItem.DropDownItems[this._blobManager.Account.AccountName].Text;
        }

        /// <summary>
        /// Responds when the user clicks on an account.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void accountsToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                ToolStripMenuItem clickedItem = (ToolStripMenuItem)e.ClickedItem;
                this.ShowMessage(string.Empty);

                if (BlobManager.AccountExists(clickedItem.Text))
                {
                    foreach (ToolStripMenuItem item in this.uiAccountsToolStripMenuItem.DropDownItems)
                    {
                        item.Checked = false;
                    }

                    clickedItem.Checked = true;
                    clickedItem.Select();
                    this.uiStatusAccount.Text = "Account: " + clickedItem.Text;
                    this.uiListViewBlobs.Clear();
                    this._blobManager.Load(clickedItem.Text);

                    this.AutoUpdateContainerList();

                }
                else
                {
                    this.ShowMessage("Unable to find the account " + clickedItem.Text + " in the configuration file.");
                }
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Displays a message in the UI.
        /// </summary>
        /// <param name="message"></param>
        private void ShowMessage(object message)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(new ParameterDelegate(ShowMessage), new object[] { message });
                return;
            }

            if (message.GetType() == typeof(Exception))
            {
                this.uiStatusMessage.Text = ((Exception)message).Message;
            }
            else
            {
                this.uiStatusMessage.Text = message.ToString();
            }
        }
        
        /// <summary>
        /// Responds when the blob manager has finished adding a blob.
        /// </summary>
        void blob_AddBlob()
        {
            // TODO Only refresh the blob list when the checkbox is set
            //this.uiListViewContainers_DoubleClick(null, null);
            this.UpdateBlobListView();
        }

        /// <summary>
        /// Responds to the blob changed event in the blob manager.
        /// </summary>
        /// <param name="item"></param>
        void blob_Changed(object item)
        {
            try
            {
                if (InvokeRequired)
                {
                    this.BeginInvoke(new ParameterDelegate(blob_Changed), new object[] { item });
                    return;
                }
                this.uiListViewBlobs.Items.Add((ListViewItem)item);
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the blob manager removes a blob.
        /// </summary>
        void blob_RemoveBlobs()
        {
            try
            {
                if (InvokeRequired)
                {
                    this.BeginInvoke(new NoParameterDelegate(blob_RemoveBlobs));
                    return;
                }
                this.uiListViewBlobs.Items.Clear();
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds to the show container event in the blob manager.
        /// </summary>
        /// <param name="item"></param>
        void container_Changed(object item)
        {
            try
            {
                if (InvokeRequired)
                {
                    this.BeginInvoke(new ParameterDelegate(container_Changed), new object[] { item });
                    return;
                }

                // add a container to the list view
                this.uiListViewContainers.Items.Add((ListViewItem)item);
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        /// <summary>
        /// Responds when the blob manager is finished loading.
        /// </summary>
        void _blobManager_Loaded()
        {
            this.uiRefreshToolStripMenuItem.Enabled = true;
            this.uiAddContainerToolStripMenuItem.Enabled = true;
        }

        /// <summary>
        /// Handles the load error event thrown by the blob manager.
        /// </summary>
        /// <param name="ex"></param>
        void _blobManager_LoadError(Exception ex)
        {
            this.UpdateUI(Globals.UpdateUiEvent.LoadError);
        }

        /// <summary>
        /// Responds to complete events from the blob manager.
        /// </summary>
        void _blobManager_Complete()
        {
            // stop the progress bar and reset it when the blob manager raises a complete event
            this.StopProgress();
        }
    }
}
